/*
 *  blob.h
 *  bgsubtraction
 *
 *  Created by a1gucis on 4/24/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
#ifndef BLOB_H
#define BLOB_H
#define BACKGROUND_BLOB_ID 0
#define BLOB_AREA 255
#define GLOBALLY_SMALL_BLOB 0.005 //#% area of the whole shilouette area is considered to be a small blob
#define BORDER_RATIO 0.4 //if blobs border ratio is > #%, fuse it.  
#define COLOR_DISTANCE_THRESHOLD 20.0 //if mahalanobis distance between two blobs color values is less than #, then fusion can be performed
#define SKIN_BLOB_MEAN_CHAN1 0.02
#define SKIN_BLOB_MEAN_CHAN2 0.14
#define SKIN_BLOB_MEAN_CHAN3 130 //useless
#define SKIN_BLOB_VAR_CHAN1 0.1536
#define SKIN_BLOB_VAR_CHAN2 0.2 
#define SKIN_BLOB_VAR_CHAN3 30 //useless
#define SKIN_BLOB_EUCLIDEAN_DIST 0.002 //max euclidean distance allowed between skin mean and blob mean, to treat blob as skin blob;
#define SKIN_BLOB_PIXELS_TO_FIND 50 //number of pixels to find, which correspond to skin pixel values;
#define DIRECTION_LEFT 0
#define DIRECTION_TOP_LEFT 1
#define DIRECTION_TOP 2
#define DIRECTION_TOP_RIGHT 3
#define DIRECTION_RIGHT 4
#define DIRECTION_BOTTOM_RIGHT 5
#define DIRECTION_BOTTOM 6
#define DIRECTION_BOTTOM_LEFT 7

#include "systeminclude.h"
#include "id.h"
#include "idgenerator.h"
#include "contourpixel.h"
#include "utils.h"
#include "jarvismarch.h"
#include <vector>
#include <iostream>
#include <math.h>
using namespace std;
class Blob {
private:
	vector<int> rowPixels; //keeps the row pixel values belonging to the blob
	vector<int> columnPixels; //keeps the column pixel values belonging to the blob
	vector<ContourPixel *> *contourPixels; //keeps outermost row pixel values, belonging to the contour of the blob
	ID *id; //unique ID of the blob
	vector<Blob *> *adjacentBlobs; //a list of neighbouring Blobs 
	int label; //label in the Image a blob corresponds to
	int topRow, bottomRow, leftCol, rightCol; //four values, defining blobs centroid
	double chan1, chan2, chan3; //3 values, defining the mean color of the blob
	bool fused;
	bool skinBlob;
	
public:
	Blob(ID *id);
	~Blob();
	int skinHits;
	int getArea();
	int getLabel();
	int getCentroidRow(); //centroid values are calculated according to topRow, bottomRow, leftCol, rightCol values
	int getCentroidCol();
	int getTopRow();
	int getBottomRow();
	int getLeftCol();
	int getRightCol();
	float getBorderRatio(Blob *blob); //number of contour Pixels, connected to blob / number of total contour Pixels
	double getChan1();
	double getChan2();
	double getChan3();
	bool isFused();
	bool isSkinBlob();
	bool hasBackgroundAsNeighbour();
	ID *getID();
	vector<int> *getRowPixels();
	vector<int> *getColumnPixels();
	vector<ContourPixel *> *getContourPixels();
	vector<Blob *> *getAdjacentBlobs();
	void addPixel(int row, int col);
	void addContourPixel(ContourPixel *contourPixel);
	void addNeighbour(Blob *neighbour); //adds a neighbour blob to the adjacentBlobs vector
	void setLabel(int label);
	void setTopRow(int topRow);
	void setBottomRow(int bottomRow);
	void setLeftCol(int leftCol);
	void setRightCol(int rightCol);
	void setID(ID *id);
	void setFused();
	void setSkin(); //sets blob to skin blob
	void setContourPixels(vector<ContourPixel *> *contourPixels);
	void setMeanColor(double chan1, double chan2, double chan3);
	void deleteNeighbour(Blob *neighbour); //deletes a neighbour blob from the adjacentBlobs vector
	void printID();
	void printMeanColor();
	
	//scans the labeledImage for blobs and adds them to blobVector. After that: calls the findMeanColorValues and 
	//gatherContourPixels function for each blob;
	static void gatherBlobs(vector<Blob *> *blobVector, IplImage *labeledImage, int bgLabel, IDGenerator *generator, IplImage *originalImage, IplImage *blobImage);
	
	//finds the neighbours of each blob. Fills the adjacentBlobs vector with neighbouring blobs. Input: vector, containing all the blobs, 
	//the labeled Image and the value for the background label. After that, calls the calibrateNeighbours function
	static void gatherNeighbours(vector<Blob *> *blobVector, IplImage *labeledImage, int bgLabel, IplImage *blobImage);
	
	//performs blob fusion over the whole blobVector
	static void doBlobFusion(vector<Blob *> **blobVector, IplImage *originalImage, int fgArea, int bgLabel);
	
	//fuses adjacent blobs, having the same label
	static bool fuseBlobsWithSameLabel(vector<Blob *> **blobVector, int bgLabel);
	
	//fuses blobs with large border ratio criterion, which is defined by BORDER_RATIO constant. Also checks for color similarity.
	//Returns true if fusions were performed,
	//else - returns false
	static bool fuseBlobsWithLargeBorderRatioAndSimilarColor(vector <Blob *> **blobVector, CvMat *inverseCovarianceMatrix);
	
	//fuses small blobs. Foreground area in pixels is necessary as an input as well
	static bool fuseSmallBlobs(vector<Blob *> **blobVector, int fgArea, int bgLabel);
	
	//fuses blobs, which have only one neighbour
	static void fuseBlobsWithOneNeighbour(vector<Blob *> **blobVector);
	
	//fuses blob1 to blob2
	static void fuseBlobs(Blob *blob1, Blob *blob2);
	
	//finds a neighbour of a particular blob. direction can be: left, top left, top, top right, right, bottom right, bottom, bottom left
	static Blob* findNeighbour(Blob *blob, vector<Blob *> *blobVector, IplImage *labeledImage, int bgLabel, int direction, IplImage *blobImage);

	//calibrates all the blobs in blobvector. (if blob1 has a neighbour blob2, then this function makes sure, that blob2 has a neighbour blob1);
	static void calibrateNeighbours(vector<Blob *> *blobVector, int bgLabel);
	
	//creates the blob given its starting pixel at row, col and its ID
	static Blob* createBlob(IplImage *image, int row, int col, ID *id, IplImage *blobImage);
	
	//fills the blobs rowPixels and columnPixels vectors, calculates the topRow, bottomRow, leftCol, rightCol values. 
	static void findMainParameters(Blob *blob, IplImage *labeledImage, int row, int col, IplImage *blobImage);
	
	//Calculates the mean color value of each blob
	static void findMeanColorValues(Blob *blob, IplImage *originalImage);
	
	//finds 8 outermost pixels, corresponding to the contour of the blob. Fills the contourRowPixels and contourColumnPixels vectors
	static void gatherContourPixels(Blob *blob, IplImage *image, int bgLabel, IplImage *blobImage);
	
	//finds the outermost pixel, corresponding to the contour of the blob. direction can be: left, top left, top, top right, right,
	//bottom right, bottom, bottom left
	static ContourPixel *findContour(Blob *blob, IplImage *image, IplImage *blobImage, int direction, int bgLabel);	
		
	
	//finds the blob, which has the minimum range from a given row, col
	//static Blob* blobMinRange(int row, int col, int label, vector<Blob *> *blobVector);
	
	//checks if ids are equal
	static bool idsEqual(Blob *firstBlob, Blob *secondBlob);
	
	//checks if mean color values of two blobs are similar using the mahalanobis distance
	static bool colorIsSimilar(Blob *firstBlob, Blob *secondBlob, CvMat *inverseCovarianceMatrix);
	
	//finds the blob in the blob vector, given it's id
	static Blob* findBlob(int r, int g, int b, vector<Blob *> *blobVector);
	
	//finds the blob position in the blobVector
	static int findBlobPos(Blob *blob, vector<Blob *> *blobVector);
	
	//checks if the blob is skin blob
	static void checkForSkinBlob(Blob *blob, IplImage *originalImage);
	
	//uses euclidean distance, to check whether chan1 and chan2 are skin channels;
	static bool isSkinColor(float chan1, float chan2);
	
	
};


#endif
